package org.lbm.flow.engine;

import org.lbm.flow.node.NodeResult;

import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;

/**
 * 工作流执行结果
 *
 * @author insist
 * @since 2025-08-01
 */
public class FlowResult {

    public enum Status {
        SUCCESS,    // 成功
        FAILED,     // 失败
        CANCELLED   // 取消
    }

    private final String flowId;
    private final Status status;
    private final Map<String, NodeResult> nodeResults;
    private final String message;
    private final Throwable cause;
    private final long executionTime;

    private FlowResult(String flowId, Status status, Map<String, NodeResult> nodeResults,
                      String message, Throwable cause, long executionTime) {
        this.flowId = flowId;
        this.status = status;
        this.nodeResults = nodeResults != null ? new HashMap<>(nodeResults) : new HashMap<>();
        this.message = message;
        this.cause = cause;
        this.executionTime = executionTime;
    }

    /**
     * 创建成功结果
     */
    public static FlowResult success(String flowId, Map<String, NodeResult> nodeResults) {
        return new FlowResult(flowId, Status.SUCCESS, nodeResults, "工作流执行成功", null, 0);
    }

    /**
     * 创建失败结果
     */
    public static FlowResult failed(String flowId, String message) {
        return new FlowResult(flowId, Status.FAILED, null, message, null, 0);
    }

    /**
     * 创建失败结果
     */
    public static FlowResult failed(String flowId, String message, Throwable cause) {
        return new FlowResult(flowId, Status.FAILED, null, message, cause, 0);
    }

    /**
     * 创建取消结果
     */
    public static FlowResult cancelled(String flowId, String reason) {
        return new FlowResult(flowId, Status.CANCELLED, null, reason, null, 0);
    }

    /**
     * 设置执行时间
     */
    public FlowResult withExecutionTime(long executionTime) {
        return new FlowResult(flowId, status, nodeResults, message, cause, executionTime);
    }

    /**
     * 获取工作流ID
     */
    public String getFlowId() {
        return flowId;
    }

    /**
     * 获取状态
     */
    public Status getStatus() {
        return status;
    }

    /**
     * 获取节点结果
     */
    public Map<String, NodeResult> getNodeResults() {
        return new HashMap<>(nodeResults);
    }

    /**
     * 获取按拓扑顺序排列的节点结果
     */
    public List<NodeResult> getOrderedNodeResults(List<String> topologicalOrder) {
        List<NodeResult> orderedResults = new ArrayList<>();
        for (String nodeId : topologicalOrder) {
            NodeResult result = nodeResults.get(nodeId);
            if (result != null) {
                orderedResults.add(result);
            }
        }
        return orderedResults;
    }

    /**
     * 获取消息
     */
    public String getMessage() {
        return message;
    }

    /**
     * 获取异常
     */
    public Throwable getCause() {
        return cause;
    }

    /**
     * 获取执行时间
     */
    public long getExecutionTime() {
        return executionTime;
    }

    /**
     * 检查是否成功
     */
    public boolean isSuccess() {
        return status == Status.SUCCESS;
    }

    /**
     * 检查是否失败
     */
    public boolean isFailed() {
        return status == Status.FAILED;
    }

    /**
     * 检查是否取消
     */
    public boolean isCancelled() {
        return status == Status.CANCELLED;
    }

    /**
     * 获取成功的节点数量
     */
    public long getSuccessCount() {
        return nodeResults.values().stream()
                .filter(NodeResult::isSuccess)
                .count();
    }

    /**
     * 获取失败的节点数量
     */
    public long getFailedCount() {
        return nodeResults.values().stream()
                .filter(NodeResult::isFailed)
                .count();
    }

    /**
     * 获取跳过的节点数量
     */
    public long getSkippedCount() {
        return nodeResults.values().stream()
                .filter(NodeResult::isSkipped)
                .count();
    }

    /**
     * 获取总节点数量
     */
    public int getTotalCount() {
        return nodeResults.size();
    }

    @Override
    public String toString() {
        return String.format("FlowResult{flowId='%s', status=%s, message='%s', " +
                           "executionTime=%dms, success=%d, failed=%d, skipped=%d, total=%d}",
                           flowId, status, message, executionTime,
                           getSuccessCount(), getFailedCount(), getSkippedCount(), getTotalCount());
    }
}
